home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-09-02 | 48.3 KB | 1,338 lines | [TEXT/CCL2] |
- ; -*- mode: CL -*- ----------------------------------------------------- ;
- ; File: defsys.l
- ; Description: A portable defsystem facility written in pure Common LISP.
- ; This is a largely extended version of the original
- ; defsystem written by Doug Rand
- ; Author: dougr@eddie.mit.edu, Joachim H. Laubsch (laubsch@hplabs.hp.com)
- ; Created: 28-Jul-89
- ; Modified: Tue Aug 11 12:04:54 1992 (Joachim H. Laubsch)
- ; Language: CL
- ; Package: DEFSYSTEM
- ;
- ;;; *************************************************************************
- ;;; Copyright (c) 1989, Hewlett-Packard Company
- ;;; All rights reserved.
- ;;;
- ;;; Use and copying of this software and preparation of derivative works
- ;;; based upon this software are permitted. Any distribution of this
- ;;; software or derivative works must comply with all applicable United
- ;;; States export control laws.
- ;;;
- ;;; This software is made available AS IS, and Hewlett-Packard Company
- ;;; makes no warranty about the software, its performance or its conformity
- ;;; to any specification.
- ;;;
- ;;; Suggestions, comments and requests for improvements are welcome
- ;;; and should be mailed to laubsch@hplabs.com.
- ;;; *************************************************************************
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (in-package "DEFSYSTEM")
- (require "P-defsys")
-
- #+:KCL(proclaim '(optimize (speed 1)))
- (proclaim '(special *suffixes*))
- #-:LUCID
- (defvar *LOAD-IF-SOURCE-NEWER* :QUERY)
- #+(and :LUCID (not :LCL4.0))
- (import 'SYSTEM:*LOAD-IF-SOURCE-NEWER*)
- #+(and :LUCID :LCL4.0)
- (import 'LCL:*LOAD-IF-SOURCE-NEWER*)
-
- (defstruct (system (:print-function print-system))
- (name "")
- (default-pathname (pathname "") :type (or cons pathname))
- (default-package *package*)
- (needed-systems nil :type list)
- (load-before-compile nil :type list)
- (module-list nil :type list)
- (needs-update nil)
- (modules (make-hash-table :size 16 :rehash-size 8 :test #'equal))
- (default-load-module t) ; t means load all
- (memo nil :type list)
- ;; generalize to other compilers
- ;; DEFAULT is the Common Lisp compiler
- (compiler #'compile-file :type function)
- ;; generalize to other loaders
- (loader #'load :type function)
- (suffixes *suffixes* :type list)
- #+:LCL4.0
- (source-file nil)
- (documentation nil :type (or NULL string))
- )
-
- (defun print-system (system stream level)
- (declare (ignore level))
- (format stream "#<System ~A>" (system-name system)))
-
- (defstruct (module (:print-function print-module))
- (name "")
- (load-before-compile nil)
- (compile-only nil)
- (load-after nil)
- (recompile-on nil)
- (pathname nil)
- (dtm 0)
- (package nil)
- (in-process nil)
- (being-loaded nil) ; to avoid recursion in loading
- (loaded nil)
- (type )
- (source-path) ; cache module-source-file
- (binary-path) ; cache module-binary-file
- ;; generalize to other compilers
- (compiler nil :type (or NULL function))
- ;; DEFAULT is the Common Lisp compiler
- ;; generalize to other loaders
- (loader nil :type (or NULL function))
- (suffixes nil :type list)
- )
-
- (defmacro domodules ((module system &key recursive-p) &rest body)
- (let ((s (gentemp)))
- `(let* ((,s ,system))
- (dolist (system-name ,(if recursive-p
- `(system-needed-systems* ,s)
- `(list ,s)))
- (let ((system (find-system system-name)))
- (dolist (module-name (system-module-list system))
- (let ((,module (module-source-file (find-module module-name system)
- system)))
- . ,body)))))))
-
- (defmacro with-package ((module system) &rest body)
- `(let ((p (or (module-package ,module) (system-default-package ,system))))
- (if p
- (let ((*package* (if (typep p 'PACKAGE)
- p
- (or (find-package p)
- (error "Unknown package ~S" p)))))
- .,body)
- (progn .,body))))
-
- (proclaim '(inline module-load-only))
- (defun module-load-only (module)
- (member (module-type module) '(:LISP-SOURCE :LISP-BINARY)))
-
- (proclaim '(inline module-not-to-be-loaded))
- (defun module-not-to-be-loaded (module)
- (declare (type module module))
- (or (module-compile-only module)
- (member (module-type module)
- '(:LISP-EXAMPLE :TEXT))))
-
- (proclaim '(inline module-not-to-be-compiled))
- (defun module-not-to-be-compiled (module)
- (declare (type module module))
- (member (module-type module)
- '(:LISP-BINARY :LISP-SOURCE :LISP-EXAMPLE :TEXT)))
-
- (defun print-module (module stream level)
- (declare (ignore level))
- (format stream "#<Module ~A>" (module-name module)))
-
- (defvar *all-systems* nil)
- (defvar *loaded-systems* nil)
-
- (defmacro undefsystem (system-name)
- (if (symbolp system-name)
- `(let ((system (find-system ',system-name nil)))
- (if system
- (setq *all-systems* (remove system *all-systems* :key #'cdr))
- (warn "System ~S was not defined." ',system-name)))
- (error "Argument should be a symbol, not ~S." system-name))
- )
-
- (defvar *relative-binary-namestring* "")
-
- (defun canonical-pathname (key arg &aux (sep #+:CCL #\: #-:CCL #\/))
- ;; If the pathname is a string, this will be the source directory.
- ;; The binary directory will default relative to it, appending the string
- ;; *relative-binary-namestring*
- (flet ((wrng-args ()
- (error "Pathname should be a string or a dotted pair of strings, not~% ~S ~S .."
- key arg)))
- (flet ((append-seperator? (s)
- (let ((ln (length s)))
- (if (zerop ln)
- (string sep)
- (if (let ((end (elt s (1- ln))))
- (or (char= end sep)
- #+MCL (char= end #\;)
- ))
- s
- (concatenate 'string s (string sep)))))))
- (flet ((pre-process-pathname (s)
- (let* ((s (expand-file-name s))
- (ln (length s)))
- (if (zerop ln)
- (wrng-args)
- (append-seperator?
- (concatenate 'string
- (append-seperator? s)
- *relative-binary-namestring*))))))
- (flet ((expand&append-sep (s)
- (append-seperator? (expand-file-name s))))
- (or (typecase arg
- (STRING (cons (expand&append-sep arg) (pre-process-pathname arg)))
- (CONS (if (and (stringp (car arg))
- (stringp (cdr arg)))
- (cons (expand&append-sep (car arg))
- (expand&append-sep (cdr arg)))))
- (PATHNAME arg)
- (T nil))
- (wrng-args)))))))
-
- (defun pre-process-options (whole-key-value-list modules-p &aux all-keys)
- (flet ((canonical-modules (ms)
- (let ((cms (if (or (stringp ms)
- (and (consp ms)
- (symbolp (car ms))
- (or (eq T (cadr ms))
- (every #'(lambda (m) (stringp m))
- (cdr ms)))))
- (list ms)
- (if (consp ms)
- ms
- (error "Wrong syntax for Module ~S" ms)))))
- (do ((cmtl cms (cdr cmtl))) ((null cmtl))
- (when (member (car cmtl) (cdr cmtl) :test #'equal)
- (error "Multiply mentioned module ~S in ~S."
- (car cmtl) (cdr whole-key-value-list))))
- cms))
-
- (av (key val keylist) ; add a value
- (let ((v (if (consp val) val (list val))))
- (do ((tl keylist (cddr tl)))
- ((null tl) (cons key (cons v keylist)))
- (when (eq (car tl) key)
- (let* ((tl1 (cdr tl))
- (v1 (if (consp (car tl1)) (car tl1) (list (car tl1)))))
- (setf (cadr tl) (remove-duplicates (append v v1)
- :from-end t
- :test #'equal))
- (return keylist))))))
-
- (canonical-systems (arg)
- (if (listp arg) arg (list arg)))
- (wrng-arg (key arg)
- (error "The system option ~S (expecting a symbol or function) was given: ~S instead"
- key arg)))
-
- (labels ((pre-process-tail (key-value-list)
- (when key-value-list
- (let ((key (car (the cons key-value-list))))
- (if (keywordp key)
- (if (consp (cdr (the cons key-value-list)))
- (let ((arg (cadr (the cons key-value-list)))
- (Rargs (cddr key-value-list)))
- (if (member key all-keys)
- (error "Multiple use of keyword ~S ~S ..." key arg)
- (push key all-keys))
- (case key
- ((:default-pathname :pathname)
- (list* key
- (canonical-pathname key arg)
- (pre-process-tail Rargs)))
- ((:load-before-compile :needed-systems)
- (list* key
- (if modules-p
- (canonical-modules arg)
- (canonical-systems arg))
- (pre-process-tail Rargs)))
- ((:recompile-on :load-after)
- (list* key
- (canonical-modules arg)
- (pre-process-tail Rargs)))
- ((:package :default-package)
- (list* key
- (string arg)
- (pre-process-tail Rargs)))
- ((:compiler :loader)
- (list* key
- (typecase arg
- (SYMBOL arg)
- (CONS (case (car (the cons arg))
- ((FUNCTION QUOTE) (eval arg))
- (T (wrng-arg key arg))))
- (T (wrng-arg key arg)))
- (pre-process-tail Rargs)))
- (:suffixes
- (list* key
- (if (consp arg)
- arg
- (cons arg arg))
- (pre-process-tail Rargs)))
- (t (list* key
- (cadr key-value-list)
- (pre-process-tail Rargs)))))
- (error "Odd length option list ~S." key-value-list))
- (error
- "Keyword expected in module-description ~S instead of ~S."
- (cdr whole-key-value-list) key))))))
- (when modules-p
- (let ((p1 (position ':load-always whole-key-value-list)))
- (when p1
- (let* ((p1-tail (nthcdr (1+ p1) whole-key-value-list))
- (arg (canonical-modules (car p1-tail))))
- (setf whole-key-value-list
- (av ':load-before-compile
- arg
- (av ':load-after
- arg
- (nconc (subseq whole-key-value-list 0 p1)
- (cdr p1-tail)))))))))
- (pre-process-tail whole-key-value-list))))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; defsystem
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (defmacro defsystem (system-name options &body modules)
- (check-type system-name symbol)
- (check-type options list)
- `(let* ((system-construct (append '(:name ,system-name)
- ',(pre-process-options options nil)))
- mod-list
- (system (apply #'make-system system-construct))
- (loader (system-loader system))
- (compiler (system-compiler system))
- (suffixes (system-suffixes system))
- (system-mods (system-modules system)))
- (dolist (module ',modules)
- (let* ((mod-construct
- (if (consp module)
- (cons ':name module)
- (if (stringp module)
- (list ':name module)
- (error "Expecting a module description instead of: ~S."
- module))))
- (module-structure
- (apply #'make-module
- (pre-process-options mod-construct t)))
- (module-name (module-name module-structure)))
- (if (member module-name mod-list :test #'equal)
- (error "Module ~S multiply defined." module-name)
- (push module-name mod-list))
- (unless (module-loader module-structure)
- (setf (module-loader module-structure)
- (if (and (module-type module-structure)
- (member (module-type module-structure)
- '(:LISP :LISP-EXAMPLE)))
- #'load
- loader)))
- (unless (module-type module-structure)
- (setf (module-type module-structure) ':LISP))
- (unless (module-compiler module-structure)
- (setf (module-compiler module-structure) compiler))
- (unless (module-suffixes module-structure)
- (setf (module-suffixes module-structure) suffixes))
- (setf (gethash (module-name module-structure) system-mods)
- module-structure) ) )
- (setf (system-module-list system) (nreverse mod-list))
- #+LCL4.0
- (when (boundp '*load-pathname*)
- (setf (system-source-file system) (namestring *load-pathname*)))
- (redefine-system ',system-name system)
- ',system-name
- )
- )
-
- (defun redefine-system (system-name system)
- (let ((system-entry (assoc system-name *all-systems*)))
- (if system-entry
- (let* ((old-system (cdr system-entry))
- (old-modules (system-modules old-system))
- (loaded t))
- ;; find out whether the old system was loaded
- (dolist (module-name (system-module-list system))
- (let ((md (gethash module-name old-modules)))
- (if (and md (module-loaded md))
- (let ((new-module (find-module module-name system)))
- (if (and (subsetp (module-load-before-compile new-module)
- (module-load-before-compile md)
- :test #'equal)
- (subsetp (module-load-after new-module)
- (module-load-after md)
- :test #'equal)
- (subsetp (module-recompile-on new-module)
- (module-recompile-on md)
- :test #'equal))
- (setf (module-loaded new-module) t
- (module-dtm new-module) (module-dtm md))
- (setf loaded nil)))
- (setf loaded nil))))
- (unless loaded
- (setf *loaded-systems* (delete system-name *loaded-systems*)))
- (setf (cdr system-entry) system))
- (push (cons system-name system) *all-systems*))))
-
- ;----------------------------------------------------------------------------;
- ; load-system
- ;------------
- ; Exported function to load a system
- ;
- (defun load-system (system-name &key reload (include-components T) preview
- (if-source-newer :load-source)
- (level 0)
- (memo-tag (list nil));; a unique id of this call
- &aux *load-verbose*)
- (declare (special *load-verbose*
- include-components if-source-newer level memo-tag))
- (flet ((load-modules (modules system)
- (dolist (module modules)
- (let ((a-module (find-module module system)))
- ;; If already loaded then only reload if needed
- (unless (module-not-to-be-loaded a-module)
- (load-if-needed a-module system reload preview))))))
- (let* ((*load-if-source-newer* if-source-newer)
- (system-entry (assoc system-name *all-systems*))
- (system (if system-entry
- (cdr system-entry)
- (load-system-definition system-name))))
- ;; if we have already loaded this system with the same memo-tag skip rest
- (when (eq (system-memo system) memo-tag)
- (return-from load-system (values)))
- (unless preview
- (format T "~%~%;;; ~V@TLoading system ~S" level system-name))
- ;; Load subsystems
- (load-needed-systems system reload preview)
- ;; if there is a :default-load-module then load only it
- (let ((lmod (system-default-load-module system)))
- (when lmod ; NIL means: don't load any module
- (load-modules
- (if (consp lmod)
- lmod
- (if (eq lmod T) ; T means: load ALL modules
- (system-module-list system)
- (list lmod)))
- system)))
- (unless preview
- (format T "~%;;; ~V@TDone loading system ~S~%" level system-name)
- (pushnew system-name *loaded-systems*)
- (setf (system-needs-update system) nil))
- (setf (system-memo system) memo-tag)
- (values))))
-
- (defun load-needed-systems (system reload preview)
- (declare (special include-components if-source-newer level memo-tag))
- (dolist (subsystem-name (system-needed-systems system))
- (let ((subsystem (find-system subsystem-name nil)))
- (unless subsystem
- (setq subsystem (load-system-definition subsystem-name :errorp t)))
- (when (and include-components
- (or reload
- (multiple-value-bind (loaded? needs-reload?)
- (SYSTEM-LOADED-P subsystem-name)
- (or (not loaded?)
- needs-reload?))))
- (load-system subsystem-name
- :reload reload
- :include-components include-components
- :preview preview
- :if-source-newer if-source-newer
- :level (+ level 2)
- :memo-tag memo-tag))))
- )
-
- ;----------------------------------------------------------------------------;
- ; load-if-needed
- ;---------------
- ; load the module of the system, possibly again, possibly just previewing
- ; returns no value
-
- (defun load-if-needed (module system &optional reload preview)
- (flet ((do-load (path)
- ;; never force to reload any :load-after module
- (let ((load-after (module-load-after module))
- (needed-systems+ (system-needed-systems*-aux system)))
- (dolist (m load-after)
- (if (stringp m)
- (multiple-value-bind (mod system)
- (find-module-among-systems m needed-systems+)
- (load-if-needed mod system nil preview))
- (load-from-system m nil preview t))))
- (if preview
- (format T "~%;;; Need to load: ~S" path)
- (let ((loader (module-loader module)))
- (unless (or (functionp loader)
- (and (symbolp loader) (fboundp loader)))
- (error "Load function ~S (of ~S) is not a defined function."
- loader system))
- (format T "~%;;; Loading file ~S" path)
- (prog1 (with-package (module system)
- (funcall loader path))
- (setf (module-loaded module) T
- (module-dtm module) (file-write-date path)))))))
- (let ((path (get-pathname module system)) R)
- (if (null path)
- (module-not-found module system)
- (when (and (not (module-being-loaded module))
- (or reload
- (not (module-loaded module))
- (module-needs-reload-p* module system)))
- (unwind-protect (setf (module-being-loaded module) t
- R (do-load path))
- (setf (module-being-loaded module) nil))))
- R)))
-
- (defun load-from-system (module-ref reload preview &optional test-load?)
- ;; MODULE-REF: (<SYSTEM> m1 m2 ...) || (<SYSTEM> t)
- (if (consp module-ref)
- (let ((modules (rest module-ref)))
- (if (eq (car (the cons modules)) 'T)
- (load-system (car (the cons module-ref))
- :reload reload :preview preview)
- (let ((sys (find-system! (car (the cons module-ref)))))
- ;; (load-needed-systems sys reload preview)
- (dolist (module-name modules)
- (let ((module (find-module module-name sys)))
- (when (not (and test-load?
- (member (module-type module)
- '(:LISP-EXAMPLE :TEXT))))
- (load-if-needed module sys reload preview))))
- )))
- (error "~S is not a module description" module-ref)))
-
-
- ;----------------------------------------------------------------------------;
- ; compile-system
- ;---------------
- ; Exported function to compile a system
- ; will try to locate the definition first
-
- (defun compile-system (system-name &rest keyword-pairs
- &key reload recompile
- (include-components T) preview
- (memo-tag (list nil)) ;; a unique id of this call
- &allow-other-keys
- &aux system compiled-modules *load-verbose*
- (level 0))
- (declare (special system compiled-modules *load-verbose* level)
- (type symbol system-name))
- (check-type system-name symbol)
- (let ((system-entry (assoc system-name *all-systems*)))
- ;; try to find and load the system definition
- (setq system (if system-entry
- (cdr system-entry)
- (load-system-definition system-name :errorp t)))
- ;; if we have already compiled this system with the same memo-tag skip rest
- (when (eq (system-memo system) memo-tag)
- (return-from compile-system (values)))
- ;; Recompile included systems
- (dolist (subsystem-name (system-needed-systems system))
- (let ((subsystem (find-system! subsystem-name)))
- (when include-components
- (unless (eq (system-memo subsystem) memo-tag)
- (unless preview (format T "~%;;; Compiling System ~S" subsystem-name))
- (compile-system subsystem-name
- :reload reload :recompile recompile
- :include-components include-components
- :preview preview :memo-tag memo-tag)))))
- ;; Compile modules:
- ;; compiled-modules = list of module-names that needed to be compiled
- (dolist (module (system-module-list system))
- (unless (module-not-to-be-compiled (find-module module system))
- (multiple-value-bind (d c)
- (apply #'compile-if-needed
- module
- (if compiled-modules
- nil ; we have already done the dependencies
- #'(lambda () ; Load Compile subsystem dependencies
- (dolist (subsystem-name (system-load-before-compile system))
- (let ((subsystem (find-system! subsystem-name)))
- (when (or reload
- (not (member subsystem-name *loaded-systems*))
- (system-needs-update subsystem))
- (load-system subsystem-name
- :reload reload
- :include-components t ; always load needed systems
- :preview preview))))))
- keyword-pairs)
- (declare (ignore d))
- (when c (push module compiled-modules)))))
- (setf (system-memo system) memo-tag)
- (if compiled-modules
- (if preview
- (format t "~%;;; In System ~S, need to compile:~%;;; ~{~A ~}"
- system-name (nreverse compiled-modules))
- (format t "~%;;; Compiled System ~S" system-name))
- (format t "~%;;; System ~S needs no compilation." system-name))
- (values)))
-
- ;----------------------------------------------------------------------------;
- ; compile-if-needed
- ;------------------
- ; return 2 values
- ; (1) the date/time of the latest compilation
- ; (2) whether or not the module was actually compiled
-
- (defun compile-if-needed (module-name
- ;; before really compiling possibly do this
- prep-thunk
- &rest keyword-pairs
- &key reload recompile preview
- needed ; if the user wants do it!
- &allow-other-keys
- &aux bpath sdtm bdtm (ddtm 0))
- (declare (special system compiled-modules))
- (macrolet ((module-set (MS-desc system)
- ;; MS-desc: (<SYSTEM> m1 m2 ...) || (<SYSTEM> t)
- `(let ((ms (cdr (the cons ,MS-desc))))
- (if (eq (car (the cons ms)) 'T)
- (system-module-list ,system)
- ms))))
- (flet ((load-dependees (modules systems)
- (dolist (name modules)
- (if (stringp name)
- (multiple-value-bind (m s)
- (find-module-among-systems name systems)
- (load-if-needed m s reload preview))
- (load-from-system name reload preview t)))))
- (let* ((module (find-module module-name system))
- (spath (let ((p (module-source-file module system)))
- (or p (error "Can't find the source file for ~S.~%" module-name)))))
- (remf keyword-pairs ':needed) ; just for call from compile-module
- ;; Do our dependents unless this module is being processed
- (unless (or (module-in-process module) (null (module-recompile-on module)))
- (unwind-protect
- ;; We don't want to recurse infinitely if one module has
- ;; a reciprocal compile relation with another so we set the
- ;; in-process flag to cause this to bottom out. The
- ;; unwind-protect makes sure it's cleaned up on error cases.
- (let ((needed-systems* (system-needed-systems*-aux system)))
- (setf (module-in-process module) T)
- (dolist (mod (module-recompile-on module))
- (if (stringp mod)
- (multiple-value-bind (m system)
- (find-module-among-systems mod needed-systems*)
- (declare (special system))
- (if (member mod compiled-modules :test #'equal)
- (setq ddtm (max (file-write-date
- (module-binary-file m system))
- ddtm))
- (multiple-value-bind (date compiled?)
- (apply #'compile-if-needed
- mod
- prep-thunk
- :allow-other-keys t
- keyword-pairs)
- (setq ddtm (max date ddtm))
- (if compiled? (setq prep-thunk nil)))))
- (let ((system (find-system (car mod))))
- (declare (special system))
- (dolist (module-name (module-set mod system))
- (unless (module-not-to-be-compiled
- (find-module module-name system))
- (multiple-value-bind (date compiled?)
- (apply #'compile-if-needed
- module-name
- prep-thunk
- :allow-other-keys t
- keyword-pairs)
- (setq ddtm (max date ddtm))
- (if compiled? (setq prep-thunk nil)))))))))
- (setf (module-in-process module) nil)))
- ;; compile the module if its binary is older than its source or dependee
- (setq bpath (module-binary-file module system)
- sdtm (file-write-date spath)
- bdtm (if (probe-file bpath) (file-write-date bpath) 0))
- (if (and (or needed (< bdtm sdtm) (< bdtm ddtm)
- (and recompile (not (member module-name compiled-modules))))
- (not (module-in-process module)))
- ;; Recompiling.. load necessary files
- (let ((needed-systems* nil)
- (recompile-on (module-recompile-on module))
- (load-before-compile (module-load-before-compile module)))
- ;; Now, do the postponed load of the subsystems
- (when prep-thunk (funcall prep-thunk))
- (when (or recompile-on load-before-compile)
- (setq needed-systems* (system-needed-systems*-aux system)))
- (load-dependees recompile-on needed-systems*)
- (load-dependees load-before-compile needed-systems*)
- (let ((universal-time (get-universal-time)))
- (unless preview
- (format T "~%;;; Compiling Module ~S (of ~S) to ~S"
- (module-name module) (system-name system) (namestring bpath))
- (let ((compiler (module-compiler module)))
- (unless (or (functionp compiler) (and (symbolp compiler) (fboundp compiler)))
- (error "Compile function ~S (of ~S) is not a defined function."
- compiler system))
- (let (compiled?)
- (unwind-protect
- (setq compiled?
- (with-package (module system)
- (apply compiler spath
- :output-file bpath
- :allow-other-keys t
- keyword-pairs)))
- ;; if an error occurs during compilation remove the partially written
- ;; file, that some compiler may leave around
- (when (and (not compiled?) (probe-file bpath))
- (delete-file bpath)))))
- (terpri))
- (setf (system-needs-update system) T)
- ;; recompiling produces a new file so it is up to date
- ;; until the point of START of compilation
- (values universal-time t)))
- ;; Not recompiling or in process..
- (values (max bdtm sdtm) nil))))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; Pathnames
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (proclaim '(inline path-source-path path-bin-path))
- (defun path-source-path (mpath)
- (if (consp mpath) (car (the cons mpath)) mpath))
-
- (defun path-bin-path (mpath)
- (if (consp mpath) (cdr (the cons mpath)) mpath))
-
- ;; return nil if file is not found
- ;; otherwise return the pathname of the newer file, unless
- ;; *LOAD-IF-SOURCE-NEWER* is :LOAD-BINARY it will the binary instead
-
- (defun get-pathname (module system)
- (let* ((module-name (make-pathname :name (module-name module)))
- (mpath (or (module-pathname module)
- (setf (module-pathname module)
- (system-default-pathname system))))
- (spath (path-source-path mpath))
- (bpath (path-bin-path mpath))
- (suffixes (module-suffixes module))
- (sname (merge-pathnames (merge-pathnames module-name spath)
- (make-pathname :type (car suffixes))))
- (bname (merge-pathnames (merge-pathnames module-name bpath)
- (make-pathname :type (cdr suffixes)))))
- (if (probe-file sname)
- (let ((sdtm (file-write-date sname)))
- (if (probe-file bname)
- (let ((bdtm (file-write-date bname)))
- ;; Both exist take newer
- (if (> sdtm bdtm)
- (if (eq *LOAD-IF-SOURCE-NEWER* :LOAD-BINARY)
- bname
- sname)
- bname))
- sname))
- (if (probe-file bname)
- bname
- nil))))
-
- (defun module-source-file (module system)
- (declare (type module module))
- (or (module-source-path module)
- (let* ((mpath (or (module-pathname module)
- (setf (module-pathname module)
- (system-default-pathname system))))
- (dir+name (merge-pathnames
- (make-pathname :name (module-name module))
- (path-source-path mpath)))
- (source-path (merge-pathnames
- dir+name
- (make-pathname
- :type (car (module-suffixes module)))))
- (probed-path (or (probe-file source-path)
- (probe-file dir+name)
- (return-from module-source-file nil))))
- (setf (module-source-path module) probed-path))))
-
- (defun module-binary-file (module system)
- (declare (type module module))
- ;; cache the value
- (or (module-binary-path module)
- (let ((mpath (or (module-pathname module)
- (setf (module-pathname module)
- (system-default-pathname system)))))
- (setf (module-binary-path module)
- (merge-pathnames
- (make-pathname :name (module-name module)
- :type (cdr (module-suffixes module)))
- (path-bin-path mpath))))) )
- ;----------------------------------------------------------------------------;
- ; compile-module
- ;---------------
- ; Compile a module and any modules which this module depends on.
- ; An attempt is made to find the system where this module was
- ; defined. By default needed modules which are loaded will
- ; not be reloaded.
-
- (defun compile-module (module-name
- &rest keyword-pairs
- &key ((:system system-name)) reload preview
- &allow-other-keys)
- (let ((system (find-system-for-module module-name system-name))
- compiled-modules)
- (declare (special system compiled-modules))
- (apply
- #'compile-if-needed
- module-name
- #'(lambda ()
- (dolist (subsystem-name (system-load-before-compile system))
- (load-system subsystem-name
- :reload reload
- :include-components t ; always load needed systems
- :preview preview)))
- :needed t ; recompile because the user wants it
- keyword-pairs)
- (values)
- ))
-
- ;----------------------------------------------------------------------------;
- ; load-module
- ;------------
- ; load a module. By default, the module will be reloaded. The keyword argument
- ; :reload may be used to avoid reload of the module and possibly all modules this
- ; module depends on. If the module description contains any :load-after
- ; modules, these will also be reloaded.
- (defun load-module (module-name
- &key
- ((:system system-name))
- (if-source-newer :load-source)
- (reload t) preview
- &aux
- (level 0)
- (*load-if-source-newer* if-source-newer)
- (system (find-system-for-module module-name system-name))
- (module (find-module module-name system)))
- (declare (special level))
- (when (or reload (not (module-loaded module)))
- (load-if-needed module
- system
- reload
- preview
- )))
-
- (defun find-system-for-module (module-name system-name)
- (cond ((null system-name)
- ;; try to find one
- (multiple-value-bind (module sys)
- (find-module-among-systems
- module-name (mapcar #'car *all-systems*))
- (declare (ignore module))
- sys))
- ((symbolp system-name) (find-system! system-name))
- (t (error "~S should be a symbol naming a defined system."
- system-name))))
-
- ;----------------------------------------------------------------------------;
- ; show-system
- ;------------
- ; The function {\tt show-system} produces a pretty output of the system
- ; description.
-
- (defun show-system (system-name &optional (stream T))
- (macrolet ((show (string val) `(when ,val (format stream ,string ,val))))
- (let* (#+(and :LUCID (not :LCL4.0)) ( SYSTEM::*GC-SILENCE* T )
- #+(and :LUCID :LCL4.0) ( LCL:*GC-SILENCE* T )
- #+Allegro ( EXCL::*GCPRINT* nil )
- (system (find-system system-name))
- (dashes "~%;;; ---------------------------------")
- (system-path (system-default-pathname system))
- *print-circle*)
- (declare (type system system))
- (format stream "~?~%;;; System: ~S is " dashes () system-name)
- (multiple-value-bind (loaded? needs-reload?)
- (SYSTEM-LOADED-P system-name)
- (format stream "~:[not ~;~]loaded." loaded?)
- (when loaded?
- (format stream "~%;;; It ~:[does'nt need~;needs~] to be reloaded." needs-reload?))
- (let ((lm (system-default-load-module system)))
- (unless (eq lm 'T) (format T "~%;;; Default-load-module: ~S" lm)))
- (show "~%;;; ~A" (system-documentation system))
- (show "~%;;; Load-before-compile: ~{~S ~}" (system-load-before-compile system))
- (show "~%;;; Needed Systems: ~{~S ~}" (system-needed-systems system))
- (show "~%;;; Default Package: ~S" (system-default-package system))
- (show "~%;;; Suffixes: ~S" (system-suffixes system))
- (unless (equal (pathname "") system-path)
- (if (consp system-path)
- (progn
- (format stream "~%;;; Default Source Path: ~S" (car system-path))
- (format stream "~%;;; Default Binary Path: ~S"
- (cdr system-path)))
- (format stream "~%;;; Default Path: ~S" system-path)))
-
- #+:LCL4.0 (show "~%;;; Source file: ~S" (system-source-file system))
- (dolist (module-name (system-module-list system))
- (show-module module-name :system system-name :verbose nil))
- (system-circular-p system-name ':load-before-compile)
- (system-circular-p system-name ':load-after)
- (format stream dashes)
- (values)))))
-
- (defun show-module (module-name &key (system nil system-p) (verbose T) (stream T))
- (macrolet ((show (string val) `(when ,val (format stream ,string ,val))))
- (multiple-value-bind (module system)
- (if system-p
- (values (find-module module-name (find-system system))
- (find-system system))
- (find-module-among-systems
- module-name (mapcar #'car *all-systems*)))
- (let ((system-path (system-default-pathname system)))
- (format stream "~%;;; Module: ~S~:[~; (of ~S)~]"
- module-name verbose (system-name system))
- (let ((type (module-type module)))
- (unless (eq type :lisp) (format t " (type ~S)" (module-type module))))
- (show " Package: ~S" (module-package module))
- (format stream "~48,8T~:[Not ~;~]Loaded" (module-loaded module))
- (let* ((spath (module-source-file module system))
- (bpath (probe-file (module-binary-file module system)))
- (sdtm (and spath (file-write-date spath)))
- (btm (and bpath (file-write-date bpath)))
- (mpath (path-source-path (module-pathname module))))
- (if spath
- (progn
- (if (null btm)
- (unless (module-not-to-be-compiled module)
- (format stream " Needs Compilation"))
- (when (> sdtm btm)
- (format stream " Needs Recompile")))
- (when (and (module-loaded module)
- (module-needs-reload-p module system))
- (format stream " Needs Reload")))
- (format stream "~%;;; Source not found in ~S"
- mpath))
- (show "~%;;; Compile-only: ~S" (module-compile-only module))
- (let* ((Load-before-compile (module-load-before-compile module))
- (Load-after (module-load-after module))
- (Load-always (intersection Load-before-compile Load-after :test #'equal)))
- (show "~%;;; Load-always: ~{~S ~}" Load-always)
- (show "~%;;; Load-before-compile: ~{~S ~}"
- (set-difference Load-before-compile Load-always :test #'equal))
- (show "~%;;; Load-after: ~{~S ~}"
- (set-difference Load-after Load-always :test #'equal)))
- (show "~%;;; Recompile-on: ~{~S ~}" (module-recompile-on module))
- (unless (or (null mpath)
- (equal mpath (path-source-path system-path)))
- (format stream "~%;;; Pathname: ~S" mpath))
- (unless (equal (module-suffixes module) (system-suffixes system))
- (format stream "~%;;; Suffixes: ~S" (module-suffixes module))))
- (values)))))
-
- ;----------------------------------------------------------------------------;
- ; module-needs-reload-p
- ;----------------------
- ; return T if module is not loaded or it is loaded but either the binary or
- ; the source is younger than the loaded version
-
- (defun module-needs-reload-p (module system)
- (declare (type module module) (type system system))
- (unless (module-not-to-be-loaded module)
- (if (module-loaded module)
- (let ((mdtm (module-dtm module))
- (spath (module-source-file module system)))
- #-:KCL (declare (fixnum mdtm) (pathname spath))
- (when spath
- (if (> (file-write-date spath) mdtm)
- ;; the source is more recent ==> T
- (return-from module-needs-reload-p
- (setf (system-needs-update system) t))
- ;; the source is older, how about the binary?
- (let ((bpath (module-binary-file module system)))
- (return-from module-needs-reload-p
- (if (and (probe-file bpath)
- (> (file-write-date bpath) mdtm))
- ;; the binary is more recent ==> T
- (setf (system-needs-update system) t)
- nil)))))
- ;; no source found
- (let ((bpath (module-binary-file module system)))
- (if (probe-file bpath)
- (if (> (file-write-date bpath) mdtm)
- (setf (system-needs-update system) t)
- nil)
- (error "Module not found ~S." (module-name module)))))
- ;; module not loaded, so certainly it needs to be loaded
- t)))
-
- (defun module-needs-reload-p* (module system)
- (or (module-needs-reload-p module system)
- (some #'(lambda (pair)
- (module-needs-reload-p (car pair) (cdr pair)))
- (module-needed-modules*-aux module system))))
-
- ;----------------------------------------------------------------------------;
- ; module-needs-recompile-p
- ;-------------------------
- ; return T if module its binary is older than its source
-
-
- (defun module-needs-recompile-p (module system)
- (declare (type module module) (type system system))
- (unless (module-not-to-be-compiled module)
- (let ((bpath (module-binary-file module system)))
- (declare (pathname bpath))
- (when (if (probe-file bpath)
- (< (file-write-date bpath)
- (file-write-date (module-source-file module system)))
- t)
- (setf (system-needs-update system) t)))))
-
- (defun module-needs-recompile-p* (module system)
- (or (module-needs-recompile-p module system)
- (some #'(lambda (pair)
- (module-needs-recompile-p (car pair) (cdr pair)))
- (module-needed-modules*-aux module system))))
-
- (defun system-needs-recompile-p (system)
- (let (clean-systems)
- (labels ((system-needs-recompile-p-aux (system)
- (if (member system clean-systems)
- nil
- (or (system-needs-update system)
- (some #'(lambda (module-name)
- (module-needs-recompile-p*
- (find-module module-name system) system))
- (system-module-list system))
- (some #'(lambda (system-name)
- (system-needs-recompile-p-aux (find-system system-name)))
- (system-needed-systems system))
-
- (progn (push system clean-systems)
- ;; (setf (system-needs-update system) nil)
- nil)
-
- ))))
- (system-needs-recompile-p-aux system))))
-
- (defun SYSTEM-COMPILED-P (system-name)
- (not (system-needs-recompile-p (find-system system-name))))
-
- (defun MODULE-COMPILED-P (module-name
- &key ((:system system-name) nil system-p))
- (declare (symbol system-name))
- (let (module system)
- (if system-p
- (setq system (find-system system-name)
- module (find-module module-name system))
- (multiple-value-setq (module system)
- (find-module-among-systems
- module-name
- (mapcar #'car *all-systems*)
- nil ; no errors
- )))
- (not (module-needs-recompile-p* module system))))
-
- ;----------------------------------------------------------------------------;
- ; system-needed-systems*
- ;-----------------------
- ; given the name of a defined system, returns the
- ; transitive closure of system-needed-systems
-
- (defun system-needed-systems* (system-name &optional (recursive-p t))
- (let ((system (find-system system-name)))
- (if recursive-p
- (system-needed-systems*-aux system)
- (system-needed-systems system))))
-
- (defun system-needed-systems*-aux (system)
- (labels ((system-needed-systems*-list (l)
- (if (null l)
- nil
- (union (system-needed-systems*-aux (find-system! (car l)))
- (system-needed-systems*-list (cdr l))))))
- (adjoin (system-name system)
- (system-needed-systems*-list (system-needed-systems system))))
- )
-
- (defun module-needed-modules* (module-name system-name &optional (recursive-p t))
- (let* ((system (find-system system-name))
- (module (find-module module-name system))
- (needed-modules (module-load-after module)))
- (if recursive-p
- (mapcar #'(lambda (x) (module-name (car x)))
- (module-needed-modules*-aux module system))
- needed-modules)))
-
- (defun module-needed-modules*-aux (module system &aux Acc)
- (macrolet ((module-set (MS-desc system)
- ;; MS-desc: (<SYSTEM> m1 m2 ...) || (<SYSTEM> t)
- `(let ((ms (cdr (the cons ,MS-desc))))
- (if (eq (car (the cons ms)) 'T)
- (system-module-list ,system)
- ms))))
- (let ((ns (system-needed-systems*-aux system)))
- (labels ((module-needed-modules*-aux-0 (module-name All-ns)
- ;;(format t "~%-aux-0 ~S ~S ~%~S" module-name All-ns Acc)
- (unless (find-if
- #'(lambda (pair)
- (string= (module-name (car pair)) module-name))
- Acc)
- (multiple-value-bind (mod system)
- (find-module-among-systems module-name All-ns t)
- ;; avoid recursion if modules need themselves
- (unless (assoc mod Acc)
- (push (cons mod system) Acc)
- (module-needed-modules*-aux-1 mod All-ns)))))
- (module-needed-modules*-aux-1 (module All-ns)
- ;;(format t "~%-aux-1 ~S ~S~%~S" module All-ns Acc)
- (dolist (module-descr (module-load-after module))
- (if (stringp module-descr)
- (module-needed-modules*-aux-0 module-descr All-ns)
- (let* ((system-name (car (the cons module-descr)))
- (system (find-system system-name))
- (new-All-ns (union (system-needed-systems system)
- (adjoin system-name All-ns))))
- (dolist (module-name (module-set module-descr system))
- (unless (module-not-to-be-loaded
- (find-module module-name system))
- (module-needed-modules*-aux-0
- module-name new-All-ns))))))))
- (module-needed-modules*-aux-1 module ns)
- (nreverse Acc)))))
-
- (defun find-module (m s &optional (errorp t))
- (declare (type system s))
- (setq m (string m))
- (let ((md (gethash m (system-modules s))))
- (if md
- md
- (when errorp (error "Module ~S not present in System ~S.~%"
- m s))
- )))
-
- (defun find-module-among-systems (m systems &optional (errorp t))
- ;; systems : (list x:symbol)
- (dolist (system-name systems)
- (let ((system (find-system system-name errorp)))
- (when system
- (let ((module (find-module m system nil)))
- (when module
- (return-from find-module-among-systems
- (values module system)))))))
- (when errorp
- (error "Module ~S not present in Systems ~S.~%"
- m systems)))
-
- ;----------------------------------------------------------------------------;
- ; find-system
- ;------------
-
- (defun find-system (system-name &optional (errorp t))
- (let ((system-entry (assoc system-name *all-systems*)))
- (if system-entry
- (cdr system-entry)
- (when errorp
- (error "No ~S system description found!"
- system-name))
- )))
-
- (defun find-system! (system-name)
- (or (find-system system-name nil)
- (load-system-definition system-name))
- )
-
- (defvar *system-directories* ())
- (defun find-system-definition-file (system-name &optional (errorp t))
- (let ((filename (format nil "~A-sys" (string system-name))))
- (dolist (pathname (if (null *default-pathname-defaults*)
- *system-directories*
- (cons *default-pathname-defaults* *system-directories*)))
- (setq pathname (expand-file-name
- (typecase pathname
- (string pathname)
- (pathname (namestring pathname))
- (t (warn "~S is neither a string nor a pathname." pathname)
- (return)))))
- (let ((binary-file (merge-pathnames
- (merge-pathnames filename
- pathname)
- (make-pathname :type (cdr *suffixes*))))
- (source-file (merge-pathnames
- (merge-pathnames filename
- pathname)
- (make-pathname :type (car *suffixes*)))))
- ;; (format t "~%~S~%~S" binary-file source-file)
- (cond ((and (probe-file binary-file)
- (probe-file source-file))
- (return-from find-system-definition-file
- (if (> (file-write-date binary-file)
- (file-write-date source-file))
- binary-file
- source-file)))
- ((probe-file binary-file)
- (return-from find-system-definition-file
- binary-file))
- ((probe-file source-file)
- (return-from find-system-definition-file
- source-file))
- ((probe-file (merge-pathnames filename pathname))
- (return-from find-system-definition-file
- (merge-pathnames filename pathname))))))
- (when errorp
- (system-definition-not-found system-name))))
-
- (defun load-system-definition (system-name &key (errorp t))
- ;; load the system-definition
- ;; return system-entry if successful
- ;; nil otherwise
- (let ((system-def (find-system-definition-file system-name errorp)))
- (if system-def
- (progn
- (format t "~%;;; Loading definition for system ~A from ~S"
- system-name system-def)
- (load system-def)
- (let ((system-entry (assoc system-name *all-systems*)))
- (if system-entry
- (cdr system-entry)
- (when errorp
- (error "No ~S system definition loaded."
- system-name)))))
- (when errorp (system-definition-not-found system-name))))
- )
- ;----------------------------------------------------------------------------;
- ; system-loaded-p
- ;----------------
- ; returns two values: value1 value2
- ; T if system is loaded T if system is loaded
- ; and needs reload
- ; Nil otherwise
-
- (defun SYSTEM-LOADED-P (system-name)
- (declare (symbol system-name))
- (let ((loaded? (member system-name *loaded-systems*))
- (system (find-system system-name)))
- (if loaded?
- (dolist (ss (system-needed-systems*-aux system)
- (values t nil))
- (let ((subsystem (find-system ss)))
- (dolist (module (let ((lm (system-default-load-module subsystem)))
- (if (eq lm 'T)
- (system-module-list subsystem)
- (if (consp lm)
- lm
- (list lm)))))
- (when (module-needs-reload-p*
- (find-module module subsystem) subsystem)
- (return-from SYSTEM-LOADED-P
- (values t (setf (system-needs-update system) t)))))))
- nil)))
-
-
- ;----------------------------------------------------------------------------;
- ; MODULE-LOADED-P
- ;----------------
- ; returns two values: value1 value2
- ; T if module is loaded T if module is loaded
- ; and needs reload
- ; Nil otherwise
-
- (defun MODULE-LOADED-P (module-name
- &key ((:system system-name) nil system-p))
- (declare (symbol system-name))
- (let (module system)
- (if system-p
- (setq system (find-system system-name)
- module (find-module module-name system))
- (multiple-value-setq (module system)
- (find-module-among-systems
- module-name
- (mapcar #'car *all-systems*)
- nil ; no errors
- )))
- (if module
- (let ((loaded? (module-loaded module)))
- (values loaded?
- (and loaded?
- (module-needs-reload-p* module system))))
- (values nil nil))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; errors
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-
- (defun system-definition-not-found (system-name)
- (declare (symbol system-name))
- (error "A definition was not found for system ~A~%; looking for file ~A-sys in: ~{~S ~}."
- system-name (symbol-name system-name) *system-directories*))
-
- (defun module-not-found (module system)
- (error "Can't find any file for module named ~S in system ~S."
- (module-name module) (system-name system))
- )
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; cycle detection
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (defun system-circular-p (system-name link)
- (let* ((system (find-system system-name))
- (context (cons system-name (system-needed-systems system)))
- (*print-circle* nil))
- (dolist (m (system-module-list system))
- (let ((cycle (detect-1-cycle
- (find-module m system)
- context
- nil
- (case link
- (:load-after #'module-load-after)
- (:load-before-compile #'module-load-before-compile)))))
- (when cycle
- (format t "~%;;; Warning: Circularity: ~S" cycle))))))
-
- (defun detect-1-cycle (node context path get-children)
- ;; node:MODULE path : ( STRING .. )
- ;; context : { SYSTEM | ( SYSTEM .. ) }
- (labels ((detect-1 (node context path)
- (let* ((mname (module-name node))
- (rpath (member mname path :test #'STRING=)))
- (if rpath
- (progn ;; (break)
- (setf (cdr rpath) nil)
- (return-from detect-1-cycle (cons mname path)))
- (let ((new-path (cons mname path)))
- (dolist (child (funcall get-children node))
- ;; child : { string | (<SYSTEM> string ..) | (<SYSTEM> t) }
- (if (consp child)
- (let ((system (find-system (car (the cons child)) nil)))
- (when system
- (let ((context (list system)))
- (dolist (gchild (if (eq (cadr child) 'T)
- (system-module-list system)
- (rest child)))
- (let ((gchild-module (find-module gchild system)))
- (when gchild-module
- (detect-1 gchild-module
- context
- new-path)))))))
- (multiple-value-bind (child-module system)
- (find-module-among-systems child context nil)
- (when child-module
- (detect-1 child-module
- (cons (system-name system)
- (system-needed-systems system))
- new-path))))))))))
- (detect-1 node context path)))
-
- #||
- (defsystem foo
- ()
- ("foo" :load-after "bar")
- ("bar" :load-after "baz")
- ("baz" :load-after "foo")
- )
- (system-circular-p 'foo ':load-after)
- (system-circular-p 'foo ':load-always)
-
- (defsystem fie
- ()
- ("foo" :load-after "bar")
- ("bar" :load-after ((fum "baz")))
- )
-
- (defsystem fum
- ()
- ("baz" :load-after ((fie t)))
- )
-
- (show-system 'fie)
- (show-system 'fum)
- ||#
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; end of defsys.l
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-